(* ================================================================== *)
(** Module d'I/O pour la gestion de tableaux partiel de booléens. *)
(* ================================================================== *)

open BplibTypes
open BitReader

(* ===================================================================== *)
(** Etant donne une chaine de caractere avec '0' ou '1' ou '*', on renvoit le tableau
    de booleen option corespondant en filtrant les caractères. 
    @param s une chaine
    @return t un tableau frais. *)
(* ===================================================================== *)
let of_string s =
  let q = Queue.create () in
  let len = String.length s in
  for i = 0 to pred len do
    let c = s.[i] in
    match c with 
    | '1' -> Queue.add (Some true) q
    | '0' -> Queue.add (Some false) q
    | '*' -> Queue.add None q
    | _ -> ()
  done;
  Array.init (Queue.length q) (fun _ -> Queue.pop q)

(* ===================================================================== *)
(** Transtypage inverse : écrire un flot partiel de booléen (bool option array) 
    dans une string 
    @param t un tableau partiel de booléen
    @return s une string fraiche *)
(* ===================================================================== *)
let to_string = 
  Array.fold_left (fun accu i -> accu^(
		     match i with
		     | Some true -> "1"
		     | Some false -> "0"
		     | None -> "*"
		   )) "" 

(* ===================================================================== *)
(** Lire un flot partiel de bool dans un fichier <b><i>ascii</b></i> en le filtrant
    @param filename le nom du fichier asci 
    @return t un tableau frais
    @raise FileNotFound si la lecture du fichier échoue *) 
(* ===================================================================== *)
let of_asci_file filename =   
  let q = Queue.create () in 
  begin
    try
      let ic = open_in filename in
      let len = in_channel_length ic in
      begin
	try
	  for i = 0 to pred len do
	    let c = input_char ic in
	    match c with 
	    | '1' -> Queue.add (Some true) q
	    | '0' -> Queue.add (Some false) q
	    | '*' -> Queue.add None q
	    | _ -> ()
	  done;
	  close_in ic;
	  Array.init (Queue.length q) (fun _ -> Queue.pop q)
	with
	| End_of_file -> 
		close_in ic;
		Array.init (Queue.length q) (fun _ -> Queue.pop q)
      end
    with
    | Sys_error _ -> raise (FileNotFound filename)
  end


(* ===================================================================== *)
(** Ecrire en <b><i>ascii</b></i> un flot de bool dans un channel
    <ul>
    <li> '1' pour true</li>
    <li> '0' pour false</li>
    <li> '*' pour None</li>
    </ul>
    @param t un tableau de booléens
    @param oc un channel écriture standard *)
(* ===================================================================== *)
let to_asci_channel t oc = 
  let taille = Array.length t in
  for i = 0 to pred taille do
    Printf.fprintf oc "%c" (char_of_bool_option t.(i))
  done;
  Printf.fprintf oc "\n"


(* ===================================================================== *)
(** Ecrire un flot partiel de bool dans un fichier <b><i>ascii</b></i>
    @param t un tableau partiel de booléens
    @param filename le nom du fichier asci *)
(* ===================================================================== *)
let to_asci_file t filename =  
  let oc = open_out filename in
  to_asci_channel t oc;
  close_out oc


(* ===================================================================== *)
(** test de conflit entre un tableau partiel et un vrai tableau.
    Si les tableaux n'ont pas la meme taille, on test les bits communs.
    @param partial_bits un tableau partiel de bits 
    @param bits un tableau de bit
    @return true si conflit, false sinon *)
(* ===================================================================== *)
let test_conflit partial_bits bits =
  let rec aux i = 
    if i < 0 then false
    else 
      match partial_bits.(i), bits.(i) with
      | Some true, false | Some false, true -> true
      | _ -> aux (pred i)
  in
  aux (pred (min (Array.length partial_bits) (Array.length bits)))

(* ===================================================================== *)
(* ===================================================================== *)
